package org.xiaov.lunasql.spring;

import lombok.NonNull;
import org.aopalliance.intercept.Joinpoint;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.beans.BeansException;
import org.xiaov.lunasql.engine.config.LunaSqlConfig;
import org.xiaov.lunasql.spring.proxy.LunaDataSourceProxy;

import javax.sql.DataSource;

/**
 * <p>
 * 数据源切面逻辑
 * </p>
 *
 * @author xiaovcloud
 * @since 2024/1/30 17:52
 */
public class LunaAutoDataSourceProxyCreator extends AbstractAutoProxyCreator {
    /**
     * lunaSqlSpringConfig
     */
    private LunaSqlConfig lunaSqlConfig;

    /**
     * 构造函数
     *
     * @param lunaSqlConfig lunaSqlSpringConfig
     */
    public LunaAutoDataSourceProxyCreator(LunaSqlConfig lunaSqlConfig) {
        this.lunaSqlConfig = lunaSqlConfig;
    }

    @Override
    protected Object[] getAdvicesAndAdvisorsForBean(@NonNull Class<?> beanClass, @NonNull String beanName, TargetSource customTargetSource) throws BeansException {
        return new Object[]{new DefaultIntroductionAdvisor((MethodInterceptor) Joinpoint::proceed)};
    }

    @Override
    @NonNull
    protected Object wrapIfNecessary(@NonNull Object bean, @NonNull String beanName, @NonNull Object cacheKey) {
        if (!(bean instanceof DataSource)) {
            return bean;
        }

        if (!(bean instanceof LunaDataSourceProxy)) {
            Object enhancer = super.wrapIfNecessary(bean, beanName, cacheKey);
            if (bean == enhancer) {
                return bean;
            }
            return createProxy((DataSource) bean);
        }

        DataSource targetDataSource = ((LunaDataSourceProxy) bean).getTargetDataSource();
        return super.wrapIfNecessary(targetDataSource, beanName, cacheKey);
    }

    private DataSource createProxy(DataSource dataSource) {
        LunaDataSourceProxy lunaDataSourceProxy = new LunaDataSourceProxy(dataSource);
        if (lunaSqlConfig == null) {
            lunaSqlConfig = new LunaSqlConfig();
        }
        lunaDataSourceProxy.setLunaConfig(lunaSqlConfig);
        return lunaDataSourceProxy;
    }
}
